home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1999 August / SGI Freeware 1999 August.iso / dist / samba.idb / usr / samba / src / source / nmbd_elections.c.z / nmbd_elections.c
Encoding:
C/C++ Source or Header  |  1998-10-28  |  12.3 KB  |  386 lines

  1. /* 
  2.    Unix SMB/Netbios implementation.
  3.    Version 1.9.
  4.    NBT netbios routines and daemon - version 2
  5.    Copyright (C) Andrew Tridgell 1994-1998
  6.    Copyright (C) Luke Kenneth Casson Leighton 1994-1998
  7.    Copyright (C) Jeremy Allison 1994-1998
  8.    
  9.    This program is free software; you can redistribute it and/or modify
  10.    it under the terms of the GNU General Public License as published by
  11.    the Free Software Foundation; either version 2 of the License, or
  12.    (at your option) any later version.
  13.    
  14.    This program is distributed in the hope that it will be useful,
  15.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.    GNU General Public License for more details.
  18.    
  19.    You should have received a copy of the GNU General Public License
  20.    along with this program; if not, write to the Free Software
  21.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22.    
  23. */
  24.  
  25. #include "includes.h"
  26.  
  27. extern int DEBUGLEVEL;
  28.  
  29. extern pstring scope;
  30.  
  31. extern pstring myname;
  32. extern fstring myworkgroup;
  33.  
  34. /* Election parameters. */
  35. extern time_t StartupTime;
  36.  
  37. /****************************************************************************
  38.   Send an election datagram packet.
  39. **************************************************************************/
  40. static void send_election_dgram(struct subnet_record *subrec, char *workgroup_name,
  41.                                 uint32 criterion, int timeup,char *server_name)
  42. {
  43.   pstring outbuf;
  44.   char *p;
  45.  
  46.   DEBUG(2,("send_election_dgram: Sending election packet for workgroup %s on subnet %s\n",
  47.     workgroup_name, subrec->subnet_name ));
  48.  
  49.   bzero(outbuf,sizeof(outbuf));
  50.   p = outbuf;
  51.   CVAL(p,0) = ANN_Election; /* Election opcode. */
  52.   p++;
  53.  
  54.   CVAL(p,0) = (criterion == 0 && timeup == 0) ? 0 : ELECTION_VERSION;
  55.   SIVAL(p,1,criterion);
  56.   SIVAL(p,5,timeup*1000); /* ms - Despite what the spec says. */
  57.   p += 13;
  58.   pstrcpy(p,server_name);
  59.   strupper(p);
  60.   p = skip_string(p,1);
  61.   
  62.   send_mailslot(False, BROWSE_MAILSLOT, outbuf, PTR_DIFF(p,outbuf),
  63.                 myname, 0,
  64.                 workgroup_name, 0x1e,
  65.                 subrec->bcast_ip, subrec->myip);
  66. }
  67.  
  68. /*******************************************************************
  69.  We found a current master browser on one of our broadcast interfaces.
  70. ******************************************************************/
  71.  
  72. static void check_for_master_browser_success(struct subnet_record *subrec,
  73.                                  struct userdata_struct *userdata,
  74.                                  struct nmb_name *answer_name,
  75.                                  struct in_addr answer_ip, struct res_rec *rrec)
  76. {
  77.   DEBUG(3,("check_for_master_browser_success: Local master browser for workgroup %s exists at \
  78. IP %s (just checking).\n", answer_name->name, inet_ntoa(answer_ip) ));
  79. }
  80.  
  81. /*******************************************************************
  82.  We failed to find a current master browser on one of our broadcast interfaces.
  83. ******************************************************************/
  84.  
  85. static void check_for_master_browser_fail( struct subnet_record *subrec,
  86.                                            struct response_record *rrec,
  87.                                            struct nmb_name *question_name,
  88.                                            int fail_code)
  89. {
  90.   char *workgroup_name = question_name->name;
  91.   struct work_record *work = find_workgroup_on_subnet(subrec, workgroup_name);
  92.  
  93.   if(work == NULL)
  94.   {
  95.     DEBUG(0,("check_for_master_browser_fail: Unable to find workgroup %s on subnet %s.=\n",
  96.           workgroup_name, subrec->subnet_name ));
  97.     return;
  98.   }
  99.  
  100.   if (strequal(work->work_group, myworkgroup))
  101.   {
  102.  
  103.     if (lp_local_master())
  104.     {
  105.       /* We have discovered that there is no local master
  106.          browser, and we are configured to initiate
  107.          an election that we will participate in.
  108.        */
  109.       DEBUG(2,("check_for_master_browser_fail: Forcing election on workgroup %s subnet %s\n",
  110.                work->work_group, subrec->subnet_name ));
  111.  
  112.       /* Setting this means we will participate when the
  113.          election is run in run_elections(). */
  114.       work->needelection = True;
  115.     }
  116.     else
  117.     {
  118.       /* We need to force an election, because we are configured
  119.          not to become the local master, but we still need one,
  120.          having detected that one doesn't exist.
  121.        */
  122.       send_election_dgram(subrec, work->work_group, 0, 0, "");
  123.     }
  124.   }
  125. }
  126.  
  127. /*******************************************************************
  128.   Ensure there is a local master browser for a workgroup on our
  129.   broadcast interfaces.
  130. ******************************************************************/
  131.  
  132. void check_master_browser_exists(time_t t)
  133. {
  134.   static time_t lastrun=0;
  135.   struct subnet_record *subrec;
  136.   char *workgroup_name = myworkgroup;
  137.  
  138.   if (!lastrun)
  139.     lastrun = t;
  140.  
  141.   if (t < (lastrun + (CHECK_TIME_MST_BROWSE * 60)))
  142.     return;
  143.  
  144.   lastrun = t;
  145.  
  146.   dump_workgroups(False);
  147.  
  148.   for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
  149.   {
  150.     struct work_record *work;
  151.  
  152.     for (work = subrec->workgrouplist; work; work = work->next)
  153.     {
  154.       if (strequal(work->work_group, workgroup_name) && !AM_LOCAL_MASTER_BROWSER(work))
  155.       {
  156.         /* Do a name query for the local master browser on this net. */
  157.         query_name( subrec, work->work_group, 0x1d,
  158.                     check_for_master_browser_success,
  159.                     check_for_master_browser_fail,
  160.                     NULL);
  161.       }
  162.     }
  163.   }
  164. }
  165.  
  166. /*******************************************************************
  167.   Run an election.
  168. ******************************************************************/
  169.  
  170. void run_elections(time_t t)
  171. {
  172.   static time_t lastime = 0;
  173.   
  174.   struct subnet_record *subrec;
  175.   
  176.   /* Send election packets once every 2 seconds - note */
  177.   if (lastime && (t - lastime < 2))
  178.     return;
  179.   
  180.   lastime = t;
  181.   
  182.   for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
  183.   {
  184.     struct work_record *work;
  185.  
  186.     for (work = subrec->workgrouplist; work; work = work->next)
  187.     {
  188.       if (work->RunningElection)
  189.       {
  190.         /*
  191.          * We can only run an election for a workgroup if we have
  192.          * registered the WORKGROUP<1e> name, as that's the name
  193.          * we must listen to.
  194.          */
  195.         struct nmb_name nmbname;
  196.  
  197.         make_nmb_name(&nmbname, work->work_group, 0x1e, scope);
  198.         if(find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME)==NULL) {
  199.           DEBUG(8,("run_elections: Cannot send election packet yet as name %s not \
  200. yet registered on subnet %s\n", namestr(&nmbname), subrec->subnet_name ));
  201.           continue;
  202.         }
  203.  
  204.         send_election_dgram(subrec, work->work_group, work->ElectionCriterion,
  205.                       t - StartupTime, myname);
  206.           
  207.         if (work->ElectionCount++ >= 4)
  208.         {
  209.           /* Won election (4 packets were sent out uncontested. */
  210.           DEBUG(2,("run_elections: >>> Won election for workgroup %s on subnet %s <<<\n",
  211.                     work->work_group, subrec->subnet_name ));
  212.  
  213.           work->RunningElection = False;
  214.  
  215.           become_local_master_browser(subrec, work);
  216.         }
  217.       }
  218.     }
  219.   }
  220. }
  221.  
  222. /*******************************************************************
  223.   Determine if I win an election.
  224. ******************************************************************/
  225.  
  226. static BOOL win_election(struct work_record *work, int version,
  227.                          uint32 criterion, int timeup, char *server_name)
  228. {  
  229.   int mytimeup = time(NULL) - StartupTime;
  230.   uint32 mycriterion = work->ElectionCriterion;
  231.  
  232.   /* If local master is false then never win
  233.      in election broadcasts. */
  234.   if(!lp_local_master())
  235.   {
  236.     DEBUG(3,("win_election: Losing election as local master == False\n"));
  237.     return False;
  238.   }
  239.  
  240.   DEBUG(4,("win_election: election comparison: %x:%x %x:%x %d:%d %s:%s\n",
  241.         version, ELECTION_VERSION,
  242.         criterion, mycriterion,
  243.         timeup, mytimeup,
  244.         server_name, myname));
  245.  
  246.   if (version > ELECTION_VERSION)
  247.     return(False);
  248.   if (version < ELECTION_VERSION)
  249.     return(True);
  250.   
  251.   if (criterion > mycriterion)
  252.     return(False);
  253.   if (criterion < mycriterion)
  254.     return(True);
  255.  
  256.   if (timeup > mytimeup)
  257.     return(False);
  258.   if (timeup < mytimeup)
  259.     return(True);
  260.  
  261.   if (strcasecmp(myname, server_name) > 0)
  262.     return(False);
  263.   
  264.   return(True);
  265. }
  266.  
  267. /*******************************************************************
  268.   Process an incoming election datagram packet.
  269. ******************************************************************/
  270.  
  271. void process_election(struct subnet_record *subrec, struct packet_struct *p, char *buf)
  272. {
  273.   struct dgram_packet *dgram = &p->packet.dgram;
  274.   int version = CVAL(buf,0);
  275.   uint32 criterion = IVAL(buf,1);
  276.   int timeup = IVAL(buf,5)/1000;
  277.   char *server_name = buf+13;
  278.   struct work_record *work;
  279.   char *workgroup_name = dgram->dest_name.name;
  280.  
  281.   server_name[15] = 0;  
  282.  
  283.   DEBUG(3,("process_election: Election request from %s at IP %s on subnet %s for workgroup %s.\n",
  284.       server_name,inet_ntoa(p->ip), subrec->subnet_name, workgroup_name ));
  285.  
  286.   DEBUG(5,("process_election: vers=%d criterion=%08x timeup=%d\n", version,criterion,timeup));
  287.  
  288.   if(( work = find_workgroup_on_subnet(subrec, workgroup_name)) == NULL)
  289.   {
  290.     DEBUG(0,("process_election: Cannot find workgroup %s on subnet %s.\n",
  291.           workgroup_name, subrec->subnet_name ));
  292.     return;
  293.   }
  294.  
  295.   if (!strequal(work->work_group, myworkgroup))
  296.   {
  297.     DEBUG(3,("process_election: ignoring election request for workgroup %s on subnet %s as this \
  298. is not my workgroup.\n", work->work_group, subrec->subnet_name ));
  299.     return;
  300.   }
  301.  
  302.   if (win_election(work, version,criterion,timeup,server_name))
  303.   {
  304.     /* We take precedence over the requesting server. */
  305.     if (!work->RunningElection)
  306.     {
  307.       /* We weren't running an election - start running one. */
  308.  
  309.       work->needelection = True;
  310.       work->ElectionCount=0;
  311.     }
  312.  
  313.     /* Note that if we were running an election for this workgroup on this
  314.        subnet already, we just ignore the server we take precedence over. */
  315.   }
  316.   else
  317.   {
  318.     /* We lost. Stop participating. */
  319.     work->needelection = False;
  320.  
  321.     if (work->RunningElection || AM_LOCAL_MASTER_BROWSER(work))
  322.     {
  323.       work->RunningElection = False;
  324.       DEBUG(3,("process_election: >>> Lost election for workgroup %s on subnet %s <<<\n",
  325.             work->work_group, subrec->subnet_name ));
  326.       if (AM_LOCAL_MASTER_BROWSER(work))
  327.         unbecome_local_master_browser(subrec, work, False);
  328.     }
  329.   }
  330. }
  331.  
  332. /****************************************************************************
  333.   This function looks over all the workgroups known on all the broadcast
  334.   subnets and decides if a browser election is to be run on that workgroup.
  335.   It returns True if any election packets need to be sent (this will then
  336.   be done by run_elections().
  337. ***************************************************************************/
  338.  
  339. BOOL check_elections(void)
  340. {
  341.   struct subnet_record *subrec;
  342.   BOOL run_any_election = False;
  343.  
  344.   for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
  345.   {
  346.     struct work_record *work;
  347.     for (work = subrec->workgrouplist; work; work = work->next)
  348.     {
  349.       run_any_election |= work->RunningElection;
  350.  
  351.       /* 
  352.        * Start an election if we have any chance of winning.
  353.        * Note this is a change to the previous code, that would
  354.        * only run an election if nmbd was in the potential browser
  355.        * state. We need to run elections in any state if we're told
  356.        * to. JRA.
  357.        */
  358.  
  359.       if (work->needelection && !work->RunningElection && lp_local_master())
  360.       {
  361.         /*
  362.          * We can only run an election for a workgroup if we have
  363.          * registered the WORKGROUP<1e> name, as that's the name
  364.          * we must listen to.
  365.          */
  366.         struct nmb_name nmbname;
  367.  
  368.         make_nmb_name(&nmbname, work->work_group, 0x1e, scope);
  369.         if(find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME)==NULL) {
  370.           DEBUG(8,("check_elections: Cannot send election packet yet as name %s not \
  371. yet registered on subnet %s\n", namestr(&nmbname), subrec->subnet_name ));
  372.           continue;
  373.         }
  374.  
  375.         DEBUG(3,("check_elections: >>> Starting election for workgroup %s on subnet %s <<<\n",
  376.               work->work_group, subrec->subnet_name ));
  377.  
  378.         work->ElectionCount = 0;
  379.         work->RunningElection = True;
  380.         work->needelection = False;
  381.       }
  382.     }
  383.   }
  384.   return run_any_election;
  385. }
  386.